package database

import (
	"fmt"
	"go_redis_service/config"
	"go_redis_service/interface/IResp"
	"go_redis_service/lib/logger"
	"go_redis_service/resp/reply"
	"runtime/debug"
	"strconv"
	"strings"
)

type Database struct {
	dbSet []*DB
}

func NewDatabase() *Database {
	mdb := &Database{}
	if config.Properties.Databases == 0 {
		config.Properties.Databases = 16
	}
	mdb.dbSet = make([]*DB, config.Properties.Databases)
	for i := range mdb.dbSet {
		singleDB := NewDB()
		singleDB.index = i
		mdb.dbSet[i] = singleDB
	}
	return mdb
}
func NewEchoDatabase() *DB {
	return NewDB()
}

func (d *Database) Exec(client IResp.Connection, args [][]byte) IResp.Reply {
	defer func() {
		if err := recover(); err != nil {
			logger.Warn(fmt.Sprintf("error occurs: %v\n%s", err, string(debug.Stack())))
		}
	}()
	cmdName := strings.ToLower(string(args[0]))
	if cmdName == "select" {
		if len(args) != 2 {
			return reply.NewTheArgNumErrReply()
		}
		return execSelect(client, d, args[1:])
	}
	dbIndex := client.GetDBIndex()
	selectedDB := d.dbSet[dbIndex]
	return selectedDB.Exec(client, args)
}

func (d *Database) AfterClientClose(c IResp.Connection) {
	logger.Info("EchoDatabase AfterClientClose")
}

func (d *Database) Close() {
	logger.Info("EchoDatabase Close")
}

func execSelect(c IResp.Connection, mdb *Database, args [][]byte) IResp.Reply {
	dbIndex, err := strconv.Atoi(string(args[0]))
	if err != nil {
		return reply.NewStadardErrReply("Err invalid DB index")
	}
	if dbIndex > len(mdb.dbSet) {
		return reply.NewStadardErrReply("Err DB index is out of range")
	}
	c.SetDBIndex(dbIndex)
	return reply.NewOkReply()
}
